package com.m1.tzolkin.model;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import com.m1.tzolkin.model.exceptions.NoAvailableSkullException;
import com.m1.tzolkin.model.exceptions.NotEnoughResourceException;
import com.m1.tzolkin.model.util.IStock;
import com.m1.tzolkin.model.util.Stock;

public class TZStock implements ITZStock {
	
	// ATTRIBUTS

	/**
	 * 
	 */
	private static final long serialVersionUID = 9140626699179974940L;
	private final IStock<TZResource> resources;
	private int skulls;
	private final PropertyChangeSupport listeners;
	
	// CONSTRUCTEUR
	
	public TZStock() {
		resources = new Stock<TZResource>();
		skulls = 0;
		listeners = new PropertyChangeSupport(this);
	}
	
	public TZStock(ITZStock c) {
		if (c == null) {
			throw new IllegalArgumentException();
		}
		resources = new Stock<TZResource>();
		add(c);
		skulls = c.getSkulls();
		listeners = new PropertyChangeSupport(this);
	}
	
	public TZStock(IStock<TZResource> s, int n) {
		if (s == null || n < 0) {
			throw new IllegalArgumentException();
		}
		resources = new Stock<TZResource>(s);
		skulls = n;
		listeners = new PropertyChangeSupport(this);
	}
	
	// REQUETES
	
	@Override
	public int getResources(TZResource r) {
		return resources.get(r);
	}
	
	@Override
	public int getSkulls() {
		return skulls;
	}

	@Override
	public boolean contains(ITZStock m) {
		if (m == null) {
			throw new IllegalArgumentException();
		}
		return resources.contains(((TZStock) m).getStock()) && m.getSkulls() == skulls;
	}

	@Override
	public boolean contains(ITZStock m, TZResource r) {
		if (m == null || r == null) {
			throw new IllegalArgumentException();
		}
		return resources.contains(((TZStock) m).getStock(), r) && skulls >= m.getSkulls();
	}

	@Override
	public boolean contains(ITZStock m, int n) {
		if (m == null) {
			throw new IllegalArgumentException();
		}
		return resources.contains(((TZStock) m).getStock()) && skulls >= m.getSkulls() - n;
	}
	
	@Override
	public boolean equals(ITZStock m) {
		return m != null && super.equals(m) && m.getSkulls() == skulls;
	}
	
	@Override
	public int getTotal() {
		return resources.getTotal() + skulls;
	}

	@Override
	public PropertyChangeListener[] getPropertyChangeListeners() {
		// TODO Stub de la méthode généré automatiquement
		return null;
	}
	
	// COMMANDES
	
	@Override
	public ITZStock addResource(TZResource r) {
		int old = getResources(r);
		resources.add(r);
		listeners.firePropertyChange(r.name(), old, getResources(r));
		return this;
	}
	
	@Override
	public ITZStock removeResource(TZResource r) {
		int old = getResources(r);
		resources.remove(r);
		listeners.firePropertyChange(r.name(), old, getResources(r));
		return this;
	}

	@Override
	public ITZStock addResource(TZResource r, int i) {
		int old = getResources(r);
		resources.add(r, i);
		listeners.firePropertyChange(r.name(), old, getResources(r));
		return this;
	}

	@Override
	public ITZStock removeResource(TZResource r, int i) {
		int old = getResources(r);
		resources.remove(r, i);
		listeners.firePropertyChange(r.name(), old, getResources(r));
		return this;
	}

	@Override
	public ITZStock addSkull() {
		++skulls;
		listeners.firePropertyChange("skulls", skulls - 1, skulls);
		return this;
	}

	@Override
	public ITZStock addSkull(int n) {
		if (n < 0) {
			throw new IllegalArgumentException();
		}
		skulls += n;
		listeners.firePropertyChange("skulls", skulls - n, skulls);
		return this;
	}

	@Override
	public ITZStock add(ITZStock m) {
		if (m == null) {
			throw new IllegalArgumentException();
		}
		for (TZResource r : TZResource.values()) {
			addResource(r, m.getResources(r));
		}
		addSkull(m.getSkulls());
		return this;
	}

	@Override
	public ITZStock removeSkull() throws NoAvailableSkullException {
		removeSkull(1);
		return this;
	}

	@Override
	public ITZStock removeSkull(int n) throws NoAvailableSkullException {
		if (skulls < n) {
			throw new NoAvailableSkullException();
		}
		skulls -= n;
		listeners.firePropertyChange("skulls", skulls - n, skulls);
		return this;
	}

	@Override
	public ITZStock remove(ITZStock m) throws NoAvailableSkullException, NotEnoughResourceException {
		if (m == null) {
			throw new IllegalArgumentException();
		}
		if (getSkulls() < m.getSkulls()) {
			throw new NoAvailableSkullException();
		}
		if (!contains(m)) {
			throw new NotEnoughResourceException();
		}
		for (TZResource r : TZResource.values()) {
			removeResource(r, m.getResources(r));
		}
		removeSkull(skulls);
		return this;
	}
	
	@Override
	public ITZStock clear() {
		for (TZResource r : TZResource.values()) {
			removeResource(r, resources.get(r));
		}
		try {
			removeSkull(skulls);
		} catch (NoAvailableSkullException e) { /* Rien */ }
		return this;
	}

	@Override
	public void addPropertyChangeListener(PropertyChangeListener l) {
		listeners.addPropertyChangeListener(l);
	}

	@Override
	public void removePropertyChangeListener(PropertyChangeListener l) {
		listeners.removePropertyChangeListener(l);
	}
	
	// OUTILS
	
	private IStock<TZResource> getStock() {
		return resources;
	}

}
